package com.bawan.vims.common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bawan.vims.common.util.DBUtil;

/**
 * <p> Title        : 通用数据库连接池 </p>
 * <p> Description	: DBConnectionPool.java </p>
 * <p> Copyright	: Copyright (c) 2015 by FITT</p>
 * <p> Author 		: JOCHEN ZHENG </p>
 * <p> Create		: 2015-1-5 11:31:52 </p> 
 * <p> version 		: 1.0 </p>
 */
public class DBConnectionPool {
	private static final Logger logger = LoggerFactory.getLogger(DBUtil.class);
	/**
	 * 遍数器
	 */
	private int checkedOut = 0;
	
	/**
	 * 数据库连接集合
	 */
	private Vector<Connection> freeConnections = new Vector<Connection>();
	
	/**
	 * 最大连接数
	 */
	private int maxConn;
	
	/**
	 * 数据库驱动
	 */
	private String driver;
	
	/**
	 * 数据库连接的JDBC URL
	 */
	private String url;
	
	/**
	 * 帐号
	 */
	private String user;
	
	/**
	 * 密码 
	 */
	private String password;

	/**
	 * 创建数据库连接池
	 * @param checkedOut
	 * @param freeConnections
	 * @param maxConn
	 * @param driver
	 * @param uRL
	 * @param user
	 * @param password
	 */
	public DBConnectionPool(String driver, String url, String user, String password, int maxConn) {
		super();
		this.maxConn = maxConn;
		this.driver = driver;
		this.url = url;
		this.user = user;
		this.password = password;
	}
	
	/**
	 * 构造函数: 建立最大连接数为2的连接池
	 * @param driver
	 * @param url
	 */
	public DBConnectionPool(String driver, String url) {
		this(driver, url, null, null, 2);
	}
	
	/**
	 * 构造函数: 建立最大连接数为 maxConn 的连接池
	 * @param driver
	 * @param url
	 * @param maxConn
	 */
	public DBConnectionPool(String driver, String url, int maxConn) {
		this(driver, url, null, null, maxConn);
	}
	
	public synchronized void freeConnection(Connection conn) {
		freeConnections.addElement(conn);
		checkedOut --;
		notifyAll();
	}
	
	/**
	 * 从连接池中获得一个可用连接.
	 * 如无空闲连接且当前连接数小于最大连接数限制,则创建新的连接;
	 * 如原来登记为可用的连接不再有效,则从向量删除之,
	 * 然后递归调用本身用以尝试新的可用连接
	 * @return
	 */
	@SuppressWarnings("resource")
	public synchronized Connection getConnection() {
		Connection conn = null;
		if (freeConnections.size() > 0) {
			//获得第一个可用连接
			conn = (Connection) freeConnections.firstElement();
			freeConnections.removeElementAt(0);
			
			try {
				if (conn.isClosed()) {
					//递归调用本身,尝试再次获取可用连接
					conn = getConnection();
				}
			} catch (SQLException e) {
				//递归调用本身,尝试再次获取可用连接
				conn = getConnection();
				logger.error(this.getClass().getName() + ".getConnection() -->" + e.getMessage(), e);
			}
		} else if (maxConn == 0 || checkedOut < maxConn) {
			conn = newConnection();
		} else {
			try {
				wait();
			} catch (InterruptedException e) {
				logger.error(this.getClass().getName() + ".getConnection() 无法获得连接： -->" + e.getMessage(), e);
			}
		}
		
		if (conn != null) {
			checkedOut ++;
		}
		logger.error(this.getClass().getName() + ".getConnection() -->checkedOut=" + checkedOut + ", maxConn=" + maxConn);
		return conn;
	}
	
	/**
	 * 从连接池中获得可用的连接.指定等待超时时间
	 * @param timeout 毫秒级别
	 * @return
	 */
	public synchronized Connection getConnection(long timeout) {
		long startTime = new Date().getTime();
		Connection conn;
		
		while((conn = getConnection()) == null) {
			try {
				wait(timeout);
			} catch (InterruptedException e) {
				logger.error(this.getClass().getName() + ".getConnection() --> timeOut=" + timeout + "," + e.getMessage(), e);
			}
			if ((new Date().getTime() - startTime) >= timeout) {
				//超时
				return null;
			}
		}
		
		return conn;
	}
	
	/**
	 * 关闭所有数据库连接
	 */
	public synchronized void release() {
		Enumeration<Connection> allConnections = freeConnections.elements();
		while(allConnections.hasMoreElements()) {
			Connection conn = (Connection)allConnections.nextElement();
			try {
				conn.close();
			} catch (SQLException e) {
				logger.error(this.getClass().getName() + ".release() --> error:" + e.getMessage(), e);
			}
		}
		freeConnections.removeAllElements();
	}
	
	/**
	 * 创建新的连接
	 * @return
	 */
	private Connection newConnection() {
		Connection conn = null;
		try {
			Class.forName(driver);
			if (user == null) {
				conn = DriverManager.getConnection(url);
			} else {
				conn = DriverManager.getConnection(url, user, password);
			}
		} catch (ClassNotFoundException e) {
			logger.error(this.getClass().getName() + ".newConnection() --> error:" + e.getMessage(), e);
			return null;
		} catch (SQLException e) {
			logger.error(this.getClass().getName() + ".newConnection() --> error:" + e.getMessage(), e);
			return null;
		}
		return conn;
	}
}
